using System;
using System.Collections.Generic;
using Oracle.ManagedDataAccess.Client;
using OracleInternal.Common;

namespace OracleInternal.BinXml
{
	internal class ObxmlInstructionState : ObxmlStateObject
	{
		internal InstructionTypes InstructionType;

		internal short m_Opcode;

		internal byte DataType;

		internal ulong TokenId;

		internal static readonly string sXmlTagOpeningBracket;

		internal static readonly string sXmlTagOpeningBracketWithSlash;

		internal static readonly string sXmlTagClosingBracket;

		internal static readonly string sXmlTagClosingBracketWithSpace;

		internal static readonly string sXmlTagClosingBracketWithSlash;

		internal static readonly string sXmlTagCommentOpen;

		internal static readonly string sXmlTagCommentClose;

		internal static readonly string sXmlTagSquareOpen;

		internal static readonly string sXmlTagSquareClose;

		internal static readonly string sXmlTagAttributeStart;

		internal static readonly string sXmlWhitespaceNewLine;

		internal static readonly string sXmlWhitespaceBlank;

		internal static readonly string sXmlWhitespaceTab;

		internal static readonly string sXmlQuote;

		internal static readonly string sXmlDocType;

		internal static readonly string sXmlPublic;

		internal static readonly string sXmlSystem;

		internal static readonly string sXmlElement;

		internal static readonly string sXmlEntity;

		internal static readonly string sXmlNotation;

		internal static readonly string sXmlNdata;

		internal static readonly string sXmlCdataStart;

		internal static readonly string sXmlCdataEnd;

		internal static readonly string sXmlAmp;

		internal static readonly string sXmlPercentage;

		internal static readonly string sXmlSemi;

		private static Dictionary<int, string> sXmlWhiteSpaceBlanks;

		private ObxmlDecodeState m_DecodeState;

		private const int DefaultTokenOrDataSize = 32768;

		internal char[] m_TextOrTokenData = new char[32768];

		internal long m_TextOrTokenDataBufferSize = 32768L;

		internal long m_TokenOrDataLength;

		internal long m_TokenOrDataOffset;

		internal long m_CsxDataLength;

		internal string m_CsxDataText;

		internal long m_CsxDataOffset;

		internal bool PreviousCharNewLine;

		internal ObxmlInstructionState(ObxmlDecodeState parent)
		{
			m_DecodeState = parent;
			ClearStateObject();
		}

		static ObxmlInstructionState()
		{
			sXmlTagOpeningBracket = "<";
			sXmlTagOpeningBracketWithSlash = "</";
			sXmlTagClosingBracket = ">";
			sXmlTagClosingBracketWithSpace = " >";
			sXmlTagClosingBracketWithSlash = "/>";
			sXmlTagCommentOpen = "<!--";
			sXmlTagCommentClose = "-->";
			sXmlTagSquareOpen = "[";
			sXmlTagSquareClose = "]";
			sXmlTagAttributeStart = "<!ATTLIST";
			sXmlWhitespaceNewLine = "\n";
			sXmlWhitespaceBlank = " ";
			sXmlWhitespaceTab = "\t";
			sXmlQuote = "\"";
			sXmlDocType = "<!DOCTYPE";
			sXmlPublic = "PUBLIC";
			sXmlSystem = "SYSTEM";
			sXmlElement = "<!ELEMENT";
			sXmlEntity = "<!ENTITY";
			sXmlNotation = "<!NOTATION";
			sXmlNdata = "NDATA";
			sXmlCdataStart = "<![CDATA[";
			sXmlCdataEnd = "]]>";
			sXmlAmp = "&";
			sXmlPercentage = "% ";
			sXmlSemi = ";";
			sXmlWhiteSpaceBlanks = new Dictionary<int, string>();
			FillBlankSpaces();
		}

		internal override void ClearStateObject()
		{
			InstructionType = InstructionTypes.None;
			m_Opcode = -1;
			TokenId = 0uL;
			DataType = 0;
			ClearStateDataObject();
		}

		internal int AppendNewLine()
		{
			if (m_DecodeState.m_IsProcessingDTD || (!PreviousCharNewLine && !m_DecodeState.PerformFullXmlParse))
			{
				Append(sXmlWhitespaceNewLine);
				PreviousCharNewLine = true;
				return 1;
			}
			return 0;
		}

		internal int Append(string data, int offset = -1, int length = -1)
		{
			int result = 0;
			if (offset != -1 && length != -1)
			{
				result = TextTokenDataCopy(data, offset, length);
			}
			else if (!string.IsNullOrEmpty(data))
			{
				length = data.Length;
				offset = 0;
				result = TextTokenDataCopy(data, offset, length);
			}
			PreviousCharNewLine = false;
			return result;
		}

		internal int Append(char[] data, int offset = -1, int length = -1)
		{
			int result = 0;
			if (offset != -1 && length != -1)
			{
				result = TextTokenDataCopy(data, offset, length);
			}
			else if (data != null)
			{
				length = data.Length;
				offset = 0;
				result = TextTokenDataCopy(data, offset, length);
			}
			PreviousCharNewLine = false;
			return result;
		}

		internal int AppendUtf8(byte[] data, ref int charCount, int offset = -1, int length = -1)
		{
			int result = 0;
			if (offset != -1 && length != -1)
			{
				result = TextTokenDataCopy(data, offset, length, out charCount);
			}
			else if (data != null)
			{
				length = data.Length;
				offset = 0;
				result = TextTokenDataCopy(data, offset, length, out charCount);
			}
			PreviousCharNewLine = false;
			return result;
		}

		private int AppendUnicode(byte[] data, ref int charCount, int offset = -1, int length = -1)
		{
			int result = 0;
			if (offset != -1 && length != -1)
			{
				result = TextTokenDataCopy(data, offset, length, out charCount, isUtf8: false);
			}
			else if (data != null)
			{
				length = data.Length;
				offset = 0;
				result = TextTokenDataCopy(data, offset, length, out charCount, isUtf8: false);
			}
			PreviousCharNewLine = false;
			return result;
		}

		private void FlushTokenTextData(int charsLength)
		{
			m_DecodeState.WriteTokenOrData(initTokenOrDataLength: true);
			ResetTextOrTokenDataLength(charsLength);
		}

		private int TextTokenDataCopy(byte[] data, int offset, int length, out int charscount, bool isUtf8 = true)
		{
			if (data == null)
			{
				return charscount = 0;
			}
			int num = (charscount = length - offset);
			if (m_TokenOrDataLength + num >= m_TextOrTokenDataBufferSize)
			{
				FlushTokenTextData(num);
			}
			num = ((!isUtf8) ? ObxmlStream.Unicode_AL16UTF16_CHARSET.ConvertBytesToChars(data, offset, length, m_TextOrTokenData, (int)m_TokenOrDataLength, ref charscount) : ObxmlStream.Utf8_AL32UTF8_CHARSET.ConvertBytesToChars(data, offset, length, m_TextOrTokenData, (int)m_TokenOrDataLength, ref charscount));
			m_TokenOrDataLength += charscount;
			m_DecodeState.m_BinXmlStream.Position += num;
			return num;
		}

		private int TextTokenDataCopy(char[] data, int offset, int length)
		{
			if (data == null)
			{
				return 0;
			}
			int num = length - offset;
			if (m_TokenOrDataLength + num >= m_TextOrTokenDataBufferSize)
			{
				FlushTokenTextData(num);
			}
			Array.Copy(data, offset, m_TextOrTokenData, m_TokenOrDataLength, length);
			m_TokenOrDataLength += num;
			return num;
		}

		private int TextTokenDataCopy(string data, int offset, int length)
		{
			if (string.IsNullOrEmpty(data))
			{
				return 0;
			}
			int num = length - offset;
			if (m_TokenOrDataLength + num >= m_TextOrTokenDataBufferSize)
			{
				FlushTokenTextData(num);
			}
			data.CopyTo(offset, m_TextOrTokenData, (int)m_TokenOrDataLength, length);
			m_TokenOrDataLength += num;
			return num;
		}

		internal void GetWhiteSpaces(char[] textOrTokenData, ObxmlNodeState ns, bool appendEndOfLine = false, bool prefixEndOfLine = false, bool SaveToNodeLevelWhiteSpaces = false)
		{
			if (textOrTokenData == null)
			{
				return;
			}
			int num = (int)m_DecodeState.m_CurrentInstruction.m_TokenOrDataLength;
			try
			{
				if (ns == null)
				{
					return;
				}
				int num2 = ns.NodeLevel - 1;
				if (num2 >= sXmlWhiteSpaceBlanks.Count)
				{
					num2 = sXmlWhiteSpaceBlanks.Count - 1;
				}
				if (appendEndOfLine)
				{
					if (prefixEndOfLine)
					{
						AppendNewLine();
						Append(sXmlWhiteSpaceBlanks[num2]);
						AppendNewLine();
					}
					else
					{
						Append(sXmlWhiteSpaceBlanks[num2]);
						AppendNewLine();
					}
				}
				else if (prefixEndOfLine)
				{
					AppendNewLine();
					Append(sXmlWhiteSpaceBlanks[num2]);
				}
				else
				{
					Append(sXmlWhiteSpaceBlanks[num2]);
				}
			}
			finally
			{
				if (SaveToNodeLevelWhiteSpaces)
				{
					int num3 = (int)m_DecodeState.m_CurrentInstruction.m_TokenOrDataLength;
					ns.m_PrefixWhiteSpaces = new string(textOrTokenData, num, num3 - num);
				}
			}
		}

		internal void AppendElementStartTagClosing(ObxmlDecodeState decodeState, bool bPreviousElement)
		{
			if (decodeState.HasBeginTagClosurePending)
			{
				if (!bPreviousElement)
				{
					Append(sXmlTagClosingBracket);
				}
				else
				{
					Append(decodeState.HasBeginTagClosurePending ? sXmlTagClosingBracketWithSlash : sXmlTagClosingBracket);
				}
				decodeState.HasBeginTagClosurePending = false;
			}
		}

		internal void AppendEmptyElementToken(ObxmlDecodeState decodeState, ObxmlNodeState ns)
		{
			string qualifiedName = ns.GetQualifiedName(decodeState);
			if (!ns.PendingDataNode && !decodeState.PerformFullXmlParse)
			{
				GetWhiteSpaces(m_TextOrTokenData, ns, appendEndOfLine: false, prefixEndOfLine: true);
				Append(sXmlTagOpeningBracket);
			}
			else
			{
				Append(sXmlTagOpeningBracket);
			}
			Append(qualifiedName);
			Append(sXmlTagClosingBracketWithSlash);
		}

		internal void AppendWhiteSpaces(ObxmlDecodeState decodeState, ObxmlNodeState ns, bool appendEndOfLine = false, bool prefixEndOfLine = false)
		{
			GetWhiteSpaces(m_TextOrTokenData, ns, appendEndOfLine, prefixEndOfLine);
		}

		internal void AppendElementStartToken(ObxmlDecodeState decodeState, ObxmlNodeState ns)
		{
			string qualifiedName = ns.GetQualifiedName(decodeState);
			m_DecodeState.HasBeginTagClosurePending = ns.ChildNodesCount == 0 && !ns.PendingDataNode;
			if (ns.m_ParentNode != null && ns.m_ParentNode.m_ElementToken != null && !decodeState.PerformFullXmlParse)
			{
				GetWhiteSpaces(m_TextOrTokenData, ns, appendEndOfLine: false, prefixEndOfLine: true, SaveToNodeLevelWhiteSpaces: true);
				Append(sXmlTagOpeningBracket);
			}
			else
			{
				Append(sXmlTagOpeningBracket);
			}
			Append(qualifiedName);
			if (!m_DecodeState.HasBeginTagClosurePending)
			{
				Append(sXmlTagClosingBracket);
			}
		}

		internal void AppendElementEndToken(ObxmlDecodeState decodeState, ObxmlNodeState ns)
		{
			bool flag = false;
			if (decodeState.HasBeginTagClosurePending && decodeState.LastNodeId == ns.NodeId)
			{
				flag = true;
				AppendElementStartTagClosing(decodeState, bPreviousElement: true);
			}
			else
			{
				string qualifiedName = ns.GetQualifiedName(decodeState);
				if (!decodeState.PerformFullXmlParse)
				{
					if (flag || ns.ChildNodesCount > 1 || (ns.ChildNodesCount == 1 && !ns.PendingDataNode))
					{
						Append(ns.m_PrefixWhiteSpaces);
					}
					Append(sXmlTagOpeningBracketWithSlash);
				}
				else
				{
					Append(sXmlTagOpeningBracketWithSlash);
				}
				Append(qualifiedName);
				Append(sXmlTagClosingBracket);
			}
			decodeState.HasBeginTagClosurePending = false;
		}

		private int ReadUtf8StringChar(int length)
		{
			int num = 0;
			if ((num = m_DecodeState.m_BinXmlStream.ReadUtf8StringChar(length, m_DecodeState.m_CurrentInstruction)) == 0)
			{
				m_DecodeState.m_CurrentInstruction.ResetTextOrTokenDataLength(length + 1);
				num = m_DecodeState.m_BinXmlStream.ReadUtf8StringChar(length, m_DecodeState.m_CurrentInstruction);
			}
			return num;
		}

		internal void AppendAttributeToken(ObxmlDecodeState decodeState, AttributeInfo attribute)
		{
			Append(attribute.GetQualifiedAttributeString(decodeState));
		}

		internal bool AppendComment(string value, int length = 0, bool prefixNewLine = false)
		{
			if (prefixNewLine)
			{
				AppendNewLine();
				Append(sXmlTagCommentOpen);
			}
			else
			{
				Append(sXmlTagCommentOpen);
			}
			if (length != 0)
			{
				ReadUtf8StringChar(length);
			}
			else if (!string.IsNullOrEmpty(value))
			{
				Append(value);
			}
			Append(sXmlTagCommentClose);
			AppendNewLine();
			return true;
		}

		internal void WriteCDATABlock(ObxmlDecodeState decodeState, string cdataValue, int length)
		{
			if (m_TextOrTokenData.Length == 0 && decodeState.m_RequestObject.m_RequestOutput.IsOutputType(InputOutputTypes.StringBuilder))
			{
				StartCDATA(decodeState);
				if (length != 0)
				{
					decodeState.WriteInputToOutput(length, useReplaceChar: false);
				}
				else if (!string.IsNullOrEmpty(cdataValue))
				{
					decodeState.WriteTextToOutput(cdataValue);
				}
				EndCDATA(decodeState);
			}
			else
			{
				StartCDATA();
				if (length != 0)
				{
					ReadUtf8StringChar(length);
				}
				else if (!string.IsNullOrEmpty(cdataValue))
				{
					Append(cdataValue);
				}
				EndCDATA();
			}
		}

		internal bool StartCDATA(ObxmlDecodeState decodeState = null)
		{
			try
			{
				if (decodeState != null)
				{
					decodeState.WriteTextToOutput(sXmlCdataStart);
					return true;
				}
				AppendString(sXmlCdataStart);
				return true;
			}
			catch (Exception ex)
			{
				OracleException.HandleError(OracleTraceLevel.Private, (OracleTraceTag)285212672, OracleTraceClassName.ObxmlInstructionState, OracleTraceFuncName.StartCDATA, ex);
				throw;
			}
		}

		internal bool EndCDATA(ObxmlDecodeState decodeState = null)
		{
			try
			{
				if (decodeState != null)
				{
					decodeState.WriteTextToOutput(sXmlCdataEnd);
					return true;
				}
				AppendString(sXmlCdataEnd);
				return true;
			}
			catch (Exception ex)
			{
				OracleException.HandleError(OracleTraceLevel.Private, (OracleTraceTag)285212672, OracleTraceClassName.ObxmlInstructionState, OracleTraceFuncName.EndCDATA, ex);
				throw;
			}
		}

		internal bool AppendString(string value, int length = 0, bool appendNewLine = false, bool appendSpace = false)
		{
			if (length != 0)
			{
				ReadUtf8StringChar(length);
			}
			else if (!string.IsNullOrEmpty(value))
			{
				Append(value);
			}
			if (appendSpace)
			{
				Append(sXmlWhitespaceBlank);
			}
			if (appendNewLine)
			{
				AppendNewLine();
			}
			return true;
		}

		internal bool AppendStringWithSpaces(string value, int length = 0, string appendSpaces = null, string prefixSpaces = null)
		{
			if (!string.IsNullOrEmpty(prefixSpaces))
			{
				Append(prefixSpaces);
			}
			if (length != 0)
			{
				ReadUtf8StringChar(length);
			}
			else if (!string.IsNullOrEmpty(value))
			{
				Append(value);
			}
			if (!string.IsNullOrEmpty(appendSpaces))
			{
				Append(appendSpaces);
			}
			return true;
		}

		internal bool AppendStringWithSpaces(string value, int length = 0, bool appendSpace = false, bool prefixSpace = false)
		{
			if (prefixSpace)
			{
				Append(sXmlWhitespaceBlank);
			}
			if (length != 0)
			{
				ReadUtf8StringChar(length);
			}
			else if (!string.IsNullOrEmpty(value))
			{
				Append(value);
			}
			if (appendSpace)
			{
				Append(sXmlWhitespaceBlank);
			}
			return true;
		}

		internal bool AppendQuoted(string value, int length = 0, bool appendSpace = false, bool prefixSpace = false)
		{
			if (prefixSpace)
			{
				Append(sXmlWhitespaceBlank);
			}
			Append(sXmlQuote);
			if (length != 0)
			{
				ReadUtf8StringChar(length);
			}
			else if (!string.IsNullOrEmpty(value))
			{
				Append(value);
			}
			Append(sXmlQuote);
			if (appendSpace)
			{
				Append(sXmlWhitespaceBlank);
			}
			return true;
		}

		internal bool AppendEntity(string name, int length = 0, bool appendSpace = false, bool prefixSpace = false)
		{
			if (prefixSpace)
			{
				Append(sXmlWhitespaceBlank);
			}
			Append(sXmlAmp);
			if (length != 0)
			{
				ReadUtf8StringChar(length);
			}
			else if (!string.IsNullOrEmpty(name))
			{
				Append(name);
			}
			Append(sXmlSemi);
			if (appendSpace)
			{
				Append(sXmlWhitespaceBlank);
			}
			return true;
		}

		private static void FillBlankSpaces()
		{
			sXmlWhiteSpaceBlanks[0] = sXmlWhitespaceBlank;
			for (int i = 1; i < 32; i++)
			{
				sXmlWhiteSpaceBlanks[i] = sXmlWhiteSpaceBlanks[i - 1] + sXmlWhitespaceBlank;
			}
		}

		internal void ClearStateDataObject()
		{
			m_CsxDataLength = 0L;
			m_CsxDataText = null;
			m_CsxDataOffset = 0L;
			m_TokenOrDataOffset = 0L;
			m_TokenOrDataLength = 0L;
		}

		internal bool ResetTokenDataConsumed(int length = -1)
		{
			if (length > 0 || m_TokenOrDataLength <= 0)
			{
				if (length >= m_TextOrTokenDataBufferSize)
				{
					m_TextOrTokenData = new char[length];
					m_TextOrTokenDataBufferSize = length;
				}
				m_TokenOrDataLength = 0L;
				m_TokenOrDataOffset = 0L;
				return true;
			}
			return false;
		}

		internal int ResetTextOrTokenDataLength(long consumedLength)
		{
			m_TokenOrDataLength -= consumedLength;
			if (!ResetTokenDataConsumed((int)consumedLength))
			{
				m_TokenOrDataOffset += consumedLength;
			}
			return (int)m_TokenOrDataLength;
		}

		internal int ResetCsxDataLength(int consumedLength)
		{
			m_CsxDataLength -= consumedLength;
			if (m_CsxDataLength == 0L)
			{
				m_CsxDataText = null;
				m_CsxDataOffset = 0L;
			}
			else
			{
				m_CsxDataOffset += consumedLength;
			}
			return (int)m_CsxDataLength;
		}

		internal bool HasMoreCsxInstructionData(out long csxDataSize)
		{
			return (csxDataSize = m_CsxDataLength) > 0;
		}

		internal bool HasMoreTokenOrData(out long tokenDataSize)
		{
			return (tokenDataSize = m_TokenOrDataLength) > 0;
		}

		internal void ResetTo(ObxmlInstructionState newState, bool copyCsxPartialBuffer)
		{
			InstructionType = newState.InstructionType;
			m_Opcode = newState.m_Opcode;
			TokenId = newState.TokenId;
		}

		internal void SetInstructionState(long countCharConsumed, ObxmlOpcode.OpcodeIds opcode, long csxOffset, ObxmlToken token = null, InstructionTypes instructionType = InstructionTypes.None)
		{
			TokenId = 0uL;
			if (token != null)
			{
				InstructionType = InstructionTypes.Token;
				TokenId = token.TokenId;
			}
			else
			{
				InstructionType = instructionType;
			}
			m_Opcode = (short)opcode;
			m_CsxDataLength = countCharConsumed;
		}
	}
}
